package com.ccp.dev.core.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 反射工具类.
 * User: 张为
 * Date: 2015/4/15
 * Time: 11:03
 */
public abstract class ReflectionUtil {
    /**
     * 获取类的声明属性
     *
     * @param clazz 类
     * @return 声明属性集合
     */
    public static Field[] getClassField(Class clazz) {
        if (clazz == null) {
            return new Field[0];
        }
        return clazz.getDeclaredFields();
    }

    /**
     * 获取类的声明属性值
     *
     * @param clazz     类
     * @param fieldName 属性名
     * @param obj       类实例
     * @return 属性值
     */
    public static Object getFieldValue(Class clazz, String fieldName, Object obj) {
        Method method = getFieldGetter(clazz, fieldName);
        if (method == null) {
            return null;
        }
        try {
            return method.invoke(obj);
        } catch (IllegalAccessException e) {
            return null;
        } catch (InvocationTargetException e) {
            return null;
        }
    }

    /**
     * 获取属性的Getter接口
     *
     * @param clazz     类
     * @param fieldName 属性名
     * @return Getter方法
     */
    public static Method getFieldGetter(Class<?> clazz, String fieldName) {
        Field[] fields = getClassField(clazz);
        if (CollectionUtil.isEmpty(fields)) {
            return null;
        }
        Method srcMethod = null;
        for (Field field : fields) {
            if (field.getName().equals(fieldName)) {
                StringBuilder getterMethod = new StringBuilder("get")
                        .append(fieldName.substring(0, 1).toUpperCase())
                        .append(fieldName.substring(1));
                try {
                    srcMethod = clazz.getMethod(getterMethod.toString());
                } catch (NoSuchMethodException e) {
                    StringBuilder isMethod = new StringBuilder("is")
                            .append(fieldName.substring(2, 3).toUpperCase())
                            .append(fieldName.substring(3));
                    try {
                        srcMethod = clazz.getMethod(isMethod.toString());
                    } catch (NoSuchMethodException e1) {
                        getterMethod = new StringBuilder("get")
                                .append(fieldName);
                        try {
                            srcMethod = clazz.getMethod(getterMethod.toString());
                        } catch (NoSuchMethodException e2) {
                            isMethod = new StringBuilder("is")
                                    .append(fieldName);
                            try {
                                srcMethod = clazz.getMethod(isMethod.toString());
                            } catch (NoSuchMethodException e3) {
                                srcMethod = null;
                            }
                        }
                    }
                }
            }
        }
        return srcMethod;
    }

    /**
     * 获取注释的类的声明属性
     *
     * @param clazz           类
     * @param annotationClass 注释类型
     * @return 注释的声明属性
     */
    public static List<Field> getAnnotationClassField(Class clazz, Class annotationClass) {
        Field[] fields = getClassField(clazz);
        if (CollectionUtil.isEmpty(fields)) {
            return null;
        }
        List<Field> fieldList = new ArrayList<Field>();
        for (Field field : fields) {
            if (field.getAnnotation(annotationClass) != null) {
                fieldList.add(field);
            }
        }
        return fieldList;
    }

    /**
     * 获取类方法
     * <p>
     * 包括public、protected、default、private等方法.<br>
     * 如果方法带参数，暂时简单比较参数个数，如果个数相等，则认为是同一方法.
     * </p>
     *
     * @param clazz      类
     * @param methodName 方法名
     * @param args       方法参数
     * @return 类方法
     */
    public static Method getClassMethod(Class clazz, String methodName, Object... args) {
        if (clazz == null) {
            return null;
        }
        Method[] methods = clazz.getDeclaredMethods();
        if (CollectionUtil.isEmpty(methods)) {
            return null;
        }
        for (Method method : methods) {
            if (method.getName().equals(methodName) && method.getParameterTypes().length == args.length) {
                return method;
            }
        }
        return null;
    }

    /**
     * 获取类方法的注解
     *
     * @param clazz      类
     * @param methodName 方法名
     * @param tClass     注解类型
     * @param args       方法参数
     * @param <T>        注解类型
     * @return 注解
     */
    public static <T extends Annotation> T getAnnotationClassMethod(Class clazz, String methodName, Class<T> tClass, Object... args) {
        Method method = getClassMethod(clazz, methodName, args);
        if (method == null) {
            return null;
        }
        return (T) method.getAnnotation(tClass);
    }
}
